/**
 * Interaction Logic Layerの概念モデル実装
 * to compile : haxe -swf-version 9 -swf Ill.swf -main Ill Ill.hx
 *
 * 2009/01 IT Planning.
 */

import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.KeyboardEvent;

/*
 * 状態を持つクラス。このクラスが各種クラスに引き回されていく。
 */
class State
{
	public var message(default, default) : String;
	public var enable(default, default) : Bool;
	public var children(default,default) : Array<Sprite>;

	public function new() {
		enable = true;
		message = "This is state message";
		children = new Array();
	}

	public function addListener( event : String, f : Dynamic ) {
		for( c in children.iterator() ) {
			c.addEventListener( event, f );
		}
	}
}

enum InteractionParameter
{
	Mouse ( m : MouseEvent );
	Keyboard ( k : KeyboardEvent );
	Any ( p : Dynamic );
}

/*
 * インタラクション（ユーザーの操作とそれらに対する視覚的応答、内部ロジック）を定義するクラス。
 * events : どのユーザーの操作に反応するか.
 * judge : 指定されたユーザの操作が発生した時に、状態を鑑みてユーザーの操作が許されるかどうかを判定.
 * acts : 視覚的応答.
 * work : 主に状態を変更する内部ロジック.
 */
class Interaction<S : State>
{
	var ctrl : Controller<S>;
	var acts : Array<S -> Void>;
	public var events(default, null) : Array<String>;
	public var name(default, default) : String;
	public var judge(default, default) : S -> Bool;
	public var work(default, default) : S -> Null<InteractionParameter> -> Void;

	public function new ( ?c : Controller<S> )
	{
		if( c != null ) {
			ctrl = c;
		}
		events = new Array();
		acts = new Array();
	}
	public function attach( c : Controller<S> ) {
		ctrl = c;
	}
	public function addReactEvent( event : String ) {
		events.push( event );
		ctrl.addListener( event );
	}
	public function addAct( act : S -> Void ) {
		acts.push( act );
	}
	public function doAct( state : S ) {
		for( a in acts ) {
			a( state );
		}
	}
	public function doWork( state : S, ?param : InteractionParameter ) : Void
	{
		if( judge( state ) ) {
			if( param != null ) {
				switch( param ) {
					case Any( v ) : // Anyの場合は視覚的応答なし
					default : doAct( state );  // 視覚的応答実行
				}
			}
			work( state, param );
		}
	}
}

/*
 * 状態とインタラクションを結びつける管理者。無駄なイベントハンドラ登録を防ぐなどする。
 */
class Controller<S : State>
{
	var inters : Hash<Interaction<S>>;
	var state : S;
	public function new( s : S) {
		state = s;
		inters = new Hash<Interaction<S>>();
	}
	public function addInteraction( i : Interaction<S> ) {
		i.attach( this );
		inters.set( i.name, i );
		for( n in i.events ) {
			addListener( n );
		}
	}
	public function getIntaraction( name : String ) {
		return inters.get( name );
	}
	public function addListener( event : String ) {
		state.addListener( event, receive );
	}
	private function receive( event : Event ) {
		for( c in inters ) {
			for( e in c.events ) {
				if( e == event.type ) {
					c.doWork( state, Mouse( cast(event) ) );
				}
			}
		}
		
	}
}

class Rectangle extends Sprite
{
	public function new ()
	{
		super();
		this.graphics.beginFill( 0x0000ff );
		this.graphics.drawRect( 50, 50, 50, 50 );
		this.graphics.endFill();
	}
}

/*
 * 具体的なインタラクションの定義。
 * マウスクリックに反応。ただし、enableの時のみ。動作すれば、右下に移動。一度実行されるとdisableになる。
 */
class SomeInteraction extends Interaction<State>
{
	public function new(  ?c : Controller<State>  ) {
		super(c);
		name = "SomeInteraction";
		events.push( MouseEvent.CLICK );
		judge = function ( state : State ) {
			return state.enable;
		};
		work = function ( state : State, param : Null<InteractionParameter> ) {
			if( param != null ) {
				switch( param ) {
					case Any( v ) : // プログラム呼び出し
		 			trace( v );
					default:        // ユーザー操作
					trace( state.message );
					state.enable = !state.enable;
				}
			}
		};
		acts.push(
			function ( state : State ) {
				for( c in state.children ) {
					c.x += 30;
					c.y += 30;
					c.alpha = 0.1;
				}
			} );
	}
}
	
class Ill
{
	public static function main() : Void
	{
		var state = new State();
		state.children.push( new Rectangle() );
		for( c in state.children ) {
			flash.Lib.current.addChild( c );
		}
		var ctrl = new Controller<State>( state );
		var inter = new SomeInteraction( ctrl );
		ctrl.addInteraction( inter );
		inter.doWork( state, Any( "Hello Interaction Logic Layer" ) );
	}
}